package com.xingchi.tornado.mybatisplus.plugins;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Base64Utils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.util.Optional;

/**
 * 默认加密实现
 * 基于AES算法实现加解密
 *
 * @author xingchi
 * @date 2024/7/23 10:38
 */
@Slf4j
public class DefaultEncryptor implements EncryptDecryptInterceptor.IEncryptor {

    /**
     * 密钥算法类型
     */
    private static final String KEY_ALGORITHM = "AES";

    /**
     * 加解密算法/工作模式/填充方式
     */
    private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";

    /**
     * 密钥长度
     */
    private static final int KEY_SIZE = 128;

    /**
     * 密钥对象
     */
    private final Key key;

    /**
     * 构造函数，使用配置的密钥
     *
     * @param secretKey 密钥字符串
     */
    public DefaultEncryptor(String secretKey) {
        try {
            if (secretKey == null || secretKey.length() < 16) {
                throw new IllegalArgumentException("密钥长度不能小于16位");
            }
            // 密钥必须是16的倍数
            byte[] keyBytes = secretKey.substring(0, 16).getBytes(StandardCharsets.UTF_8);
            this.key = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
        } catch (Exception e) {
            log.error("初始化加密器失败", e);
            throw new RuntimeException("初始化加密器失败", e);
        }
    }

    /**
     * 构造函数，自动生成密钥
     */
    public DefaultEncryptor() {
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
            keyGenerator.init(KEY_SIZE);
            SecretKey secretKey = keyGenerator.generateKey();
            this.key = new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);
            log.info("自动生成加密密钥: {}", Base64Utils.encodeToString(secretKey.getEncoded()));
        } catch (NoSuchAlgorithmException e) {
            log.error("初始化加密器失败", e);
            throw new RuntimeException("初始化加密器失败", e);
        }
    }

    @Override
    public String encrypt(String content) {
        return Optional.ofNullable(content)
                .map(c -> {
                    try {
                        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
                        cipher.init(Cipher.ENCRYPT_MODE, key);
                        byte[] encryptBytes = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
                        return Base64Utils.encodeToString(encryptBytes);
                    } catch (Exception e) {
                        log.error("加密失败", e);
                        return content;
                    }
                })
                .orElse(null);
    }

    @Override
    public String decrypt(String content) {
        return Optional.ofNullable(content)
                .map(c -> {
                    try {
                        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
                        cipher.init(Cipher.DECRYPT_MODE, key);
                        byte[] decryptBytes = cipher.doFinal(Base64Utils.decodeFromString(content));
                        return new String(decryptBytes, StandardCharsets.UTF_8);
                    } catch (Exception e) {
                        log.error("解密失败", e);
                        return content;
                    }
                })
                .orElse(null);
    }
}
